package com.ruoyi.common.utils.bean;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.exception.UtilException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.*;

@Slf4j
@Component
public class BeanTransUtils {

    @Autowired
    private ObjectMapper objectMapper;

    public <T>T beanTransform(Object obj, Class<T> clazz) {
        if(obj == null){
            return null;
        }
        try {
            String str = objectMapper.writeValueAsString(obj);
            return objectMapper.readValue(str, clazz);
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw new UtilException("类型转换错误");
        }
    }

    public <T> List<T> beanListTransform(List list, Class<T> clazz) {
        if(list == null){
            return null;
        }
        try {
            String str = objectMapper.writeValueAsString(list);
            return objectMapper.readValue(str, getCollectionType(List.class, clazz));
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw new UtilException("集合类型转换错误");
        }
    }

    public <T>T strTransToBean(String str, Class<T> clazz) {
        try {
            if(StringUtils.isBlank(str)){
                return null;
            }
            return objectMapper.readValue(str, clazz);
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw new UtilException("类型转换错误");
        }
    }

    public <T>List<T> strTransToList(String str, Class<T> clazz) {
        try {
            if(StringUtils.isBlank(str)){
                return null;
            }
            return objectMapper.readValue(str, getCollectionType(List.class, clazz));
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw new UtilException("集合类型转换错误");
        }
    }

    public Map<String, Object> beanToMap(Object obj) {
        if(obj == null){
            return null;
        }
        try {
            String str = objectMapper.writeValueAsString(obj);
            Map<String, Object> map = objectMapper.readValue(str, HashMap.class);
            //手动去除value为null的值
            map.entrySet().removeIf(entry -> entry.getValue() == null);
            return map;
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw new UtilException("类型转换错误");
        }
    }


    private JavaType getCollectionType(Class<?> collectionClass, Class<?> ...elementClasses){
        return objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    public <T> T  beanTransformDate(Object object,Class<T> valueType) throws IOException {
        String str = objectMapper.writeValueAsString(object);
        return objectMapper.readValue(str, valueType);
    }

    public String beanToString(Object obj) {
        if(obj == null){
            return "{}";
        }
        try {
            return objectMapper.writeValueAsString(obj);
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw new UtilException("类型转换错误");
        }
    }

    public String[] getNullPropertyNames(Object source) {
        final BeanWrapper src = new BeanWrapperImpl(source);
        java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
        Set emptyNames = new HashSet();
        for(java.beans.PropertyDescriptor pd : pds) {
            //check if value of this property is null then add it to the collection
            Object srcValue = src.getPropertyValue(pd.getName());
            if (srcValue == null) {//特定字符写在此处过滤，收集不需要copy的字段列表。此处过滤null为例
                emptyNames.add(pd.getName());
            }
        }
        String[] result = new String[emptyNames.size()];
        return (String[]) emptyNames.toArray(result);
    }
}
